import asyncio
import os
import uuid
from typing import List
from uuid import UUID

from dotenv import load_dotenv
from fastapi_mail import MessageSchema, ConnectionConfig, FastMail, MessageType
from pydantic import BaseModel, EmailStr

load_dotenv()
# Global constants
SENDER_MAIL = os.environ['VERIFICATION_MAIL']
SMTP_SERVER = os.environ['SMTP_SERVER']
SMTP_PORT = int(os.environ['SMTP_PORT'])
MAIL_USERNAME = os.environ['VERIFICATION_MAIL']
MAIL_PASSWORD = os.environ['VERIFICATION_MAIL_PASSWORD']
BASE_URI = os.environ['BASE_URI']

conf = ConnectionConfig(
    MAIL_USERNAME=MAIL_USERNAME,
    MAIL_PASSWORD=MAIL_PASSWORD,
    MAIL_FROM=SENDER_MAIL,
    MAIL_PORT=SMTP_PORT,
    MAIL_SERVER=SMTP_SERVER,
    MAIL_STARTTLS=False,
    MAIL_SSL_TLS=False,
    USE_CREDENTIALS=False,
    VALIDATE_CERTS=False
)


class EmailSchema(BaseModel):
    email: List[EmailStr]


async def send_email_to(
        email: str, username: str, user_uuid: UUID
) -> None:
    subject = "Подтверждение почты для пользователя {}".format(username)
    url = '{}/verification/{}'.format(BASE_URI, user_uuid)
    body = 'Чтобы подтвердить почту перейдите по ссылке: <a href="{url}">{url}</a>'.format(url=url)
    recipients = EmailSchema(email=[email])
    message = MessageSchema(
        subject=subject,
        recipients=recipients.email,
        body=body,
        subtype=MessageType.html
    )

    fm = FastMail(conf)
    await fm.send_message(message)


async def recover_password(email: str, username: str, code: UUID):
    subject = "Востановление пароля для пользователя {}".format(username)
    url = '{}/newpass/{}'.format(BASE_URI, code)
    body = 'Чтобы востановить пароль перейдите по ссылке: <a href="{url}">{url}</a>'.format(url=url)
    recipients = EmailSchema(email=[email])
    message = MessageSchema(
        subject=subject,
        recipients=recipients.email,
        body=body,
        subtype=MessageType.html
    )

    fm = FastMail(conf)
    await fm.send_message(message)


async def anyway_recover_password(email: str, username: str, code: UUID):
    while True:
        try:
            await recover_password(email, username, code)
            break
        except:
            await asyncio.sleep(10)


async def anyway_send_email_to(email: str, username: str, user_uuid: UUID):
    while True:
        try:
            await send_email_to(email, username, user_uuid)
            break
        except:
            await asyncio.sleep(10)


async def main():
    await send_email_to("denismir423@gmail.com", "denis", uuid.uuid4())


if __name__ == "__main__":
    asyncio.run(main())
